package com.suncnpap.statistics.aspect;

import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ApplicationObjectSupport;
import org.springframework.core.NamedThreadLocal;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSON;
import com.app.util.beanutil.BeanUtil;
import com.app.util.common.Constants;
import com.app.util.common.IPUtil;
import com.app.util.common.RequestUtil;
import com.app.util.common.SpringUtil;
import com.app.util.common.UuidUtil;
import com.suncnpap.base.common.GlobaUser;
import com.suncnpap.statistics.annotation.LogType;
import com.suncnpap.statistics.annotation.SysLog;
import com.suncnpap.statistics.model.WorkLog;
import com.suncnpap.statistics.service.WorkLogService;
import com.suncnpap.system.model.Admin;
import com.suncnpap.system.model.Menu;
import com.suncnpap.system.service.AdminService;
import com.suncnpap.system.service.MenuRoleService;
import com.suncnpap.system.service.MenuService;

/**
 * 日志 切点类
 */
@Aspect
@Component
public class OperateLogAspect {
	
	private  static  final Logger log = LoggerFactory.getLogger(OperateLogAspect.class);
	
	private static final ThreadLocal<Long> beginTimeThreadLocal = new NamedThreadLocal<Long>("ThreadLocal beginTime");
	private static final ThreadLocal<WorkLog> logThreadLocal = new NamedThreadLocal<WorkLog>("ThreadLocal log");
	
	
	
	@Autowired
	WorkLogService workLogService;
	
	@Autowired
	AdminService adminService;
	
	@Autowired
	private ThreadPoolTaskExecutor threadPoolTaskExecutor;
	
	
	/**
	 * Controller层切点 注解拦截
	 */
	@Pointcut("@annotation(com.suncnpap.statistics.annotation.SysLog)")
	public void sysLogPC(){} 
	
	/**
	 * 方法规则拦截
	 */
	@Pointcut("execution(* com.suncnpap.**.controller.*Controller.*(..))")
	public void sysLogPointerCut(){}
	
	
	/**
	 * 前置通知 用于拦截Controller层记录用户的操作的开始时间
	 * @param joinPoint 切点
	 * @throws InterruptedException 
	 */
	@Before("sysLogPC()")
	public void doBefore(JoinPoint joinPoint) throws InterruptedException{
		
		WorkLog workLog = new WorkLog();
//				
//		
		HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
		//获取方法上的注解
		SysLog sysLog = getSysLogAnnotation(joinPoint);
		
		String token = request.getHeader("token");
		String strUserId = request.getParameter("strUserId");
		String strSchoolId = request.getParameter("strSchoolId");
		String strId = "";
		String strUserName = "";
		if(token!=null && !token.equals("")){
			strUserName = GlobaUser.getStrCname(request.getHeader("token"));
			strId = GlobaUser.getStrId(request.getHeader("token"));
			strSchoolId = GlobaUser.getStrSchoolId(request.getHeader("token"));
		}else if(!strUserId.equals("")){
			Admin admin = adminService.findByUserId(strUserId, strSchoolId);
			if(admin!=null) {
				strUserName = admin.getStrName();
				strId = admin.getStrId();
				strSchoolId = admin.getStrSchoolId();
			}
		}
		
		if(sysLog != null && !strId.equals("")) {
			workLog.setStrUserName(strUserName);
			if(sysLog.type().equals(LogType.CATALOGUING)){
				workLog.setIntCataloguing(1);
			}else if(sysLog.type().equals(LogType.BOOKMODIFY)){
				workLog.setIntBookBorrow(1);
			}else if(sysLog.type().equals(LogType.BOOKBORROW)){
				workLog.setIntReturnBook(1);  
			}else if(sysLog.type().equals(LogType.RETURNBOOK)){
				workLog.setIntBookModify(1);
			}else if(sysLog.type().equals(LogType.JOURNALCATALOGUING)){
				workLog.setIntJournalCataloguing(1); 
			}else if(sysLog.type().equals(LogType.JOURNALBORROW)){
				workLog.setIntJournalBorrow(1);
			}else if(sysLog.type().equals(LogType.RETURNJOURNAL)){
				workLog.setIntReturnJournal(1);  
			}else if(sysLog.type().equals(LogType.HANDLECARD)){
				workLog.setIntHandleCard(1); 
			}
			workLog.setStrUserId(strId);
			workLog.setStrSchoolId(strSchoolId);
			workLog.setDtCreatDate(new Date());
			workLog.setStrId(UuidUtil.get32UUID());
		}
		logThreadLocal.set(workLog);

	}
	//@Around("sysLogPC()")
	//public Object aroundLog(ProceedingJoinPoint joinpoint){  
	//    Object result = null;
	//	try {  
	//	    result = joinpoint.proceed();  		    
	//	} catch (Throwable e) {  
	//	    e.printStackTrace();  
	//	}  
	//	return result;
	//}
	
	
	/**
	 * 后置通知 用于拦截Controller层记录用户的操作
	 * @param joinPoint 切点
	 */
	@After("sysLogPC()")
	public void doAfter(JoinPoint joinPoint) {
		
		HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
		
		
		WorkLog workLog = logThreadLocal.get();
		
		
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        
    	// debu模式下打印JVM信息。
//    	long beginTime = beginTimeThreadLocal.get();//得到线程绑定的局部变量（开始时间）  
    	Date endTime = new Date();
    	
    	
		//获取方法上的注解
		SysLog sysLog = getSysLogAnnotation(joinPoint);
		
		String token = request.getHeader("token");
		String strUserId = request.getParameter("strUserId");
		String strSchoolId = request.getParameter("strSchoolId");
		String strId = "";
		String strUserName = "";
		if(token!=null && !token.equals("")){
			strUserName = GlobaUser.getStrCname(request.getHeader("token"));
			strId = GlobaUser.getStrId(request.getHeader("token"));
			strSchoolId = GlobaUser.getStrSchoolId(request.getHeader("token"));
		}else if(!strUserId.equals("")){
			Admin admin = adminService.findByUserId(strUserId, strSchoolId);
			if(admin!=null) {
				strUserName = admin.getStrName();
				strId = admin.getStrId();
				strSchoolId = admin.getStrSchoolId();
			}
		}
		
		if(sysLog != null && !strId.equals("")) {
			workLog.setStrUserName(strUserName);
			if(sysLog.type().equals(LogType.CATALOGUING)){
				workLog.setIntCataloguing(1);
			}else if(sysLog.type().equals(LogType.BOOKMODIFY)){
				workLog.setIntBookBorrow(1);
			}else if(sysLog.type().equals(LogType.BOOKBORROW)){
				workLog.setIntReturnBook(1);  
			}else if(sysLog.type().equals(LogType.RETURNBOOK)){
				workLog.setIntBookModify(1);
			}else if(sysLog.type().equals(LogType.JOURNALCATALOGUING)){
				workLog.setIntJournalCataloguing(1); 
			}else if(sysLog.type().equals(LogType.JOURNALBORROW)){
				workLog.setIntJournalBorrow(1);
			}else if(sysLog.type().equals(LogType.RETURNJOURNAL)){
				workLog.setIntReturnJournal(1);  
			}else if(sysLog.type().equals(LogType.HANDLECARD)){
				workLog.setIntHandleCard(1); 
			}
			workLog.setStrUserId(strId);
			workLog.setStrSchoolId(strSchoolId);
			workLog.setDtCreatDate(endTime);
			workLog.setStrId(UuidUtil.get32UUID());
			threadPoolTaskExecutor.execute(new WorkLogThread(workLog, workLogService));
		}
    	
       
 
	}
	
	/**
	 *  异常通知 
	 * @param joinPoint
	 * @param e
	 */
	@AfterThrowing(pointcut = "sysLogPC()", throwing = "e")  
	public  void doAfterThrowing(JoinPoint joinPoint, Throwable e) throws Throwable{
		WorkLog workLog = logThreadLocal.get();
		
	}
	
	
	/**
	 * 获取注解中对方法的描述信息 用于Controller层注解
	 * 
	 * @param joinPoint 切点
	 * @return 方法描述
	 */
	public SysLog getSysLogAnnotation(JoinPoint joinPoint) {
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		Method method = signature.getMethod();
		SysLog sysLog = method.getAnnotation(SysLog.class);
		return sysLog;
	}
	
	
	public Object invokeFindById(String modelEntity,HttpServletRequest request,String methodName,String strId) {
		try {
			String lowerClassName = modelEntity.substring(0, 1).toLowerCase() + modelEntity.substring(1, modelEntity.length());
			String serviceName = lowerClassName + "Service";
			Object objService = SpringUtil.getBean(serviceName, request.getServletContext());
			Method m = objService.getClass().getDeclaredMethod(methodName,String.class);
			//反射调用方法，methodParam:方法参数
			Object obj = m.invoke(objService, strId);
			return obj;
		}catch(Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 保存日志线程
	 * 
	 * @author lin.r.x
	 *
	 */
	private static class WorkLogThread implements Runnable {
		private WorkLog workLog;
		private WorkLogService workLogService;

		public WorkLogThread(WorkLog workLog, WorkLogService workLogService) {
			this.workLog = workLog;
			this.workLogService = workLogService;
		}

		@Override
		public void run() {
			workLogService.add(workLog);		
		}
	}
	
	/**
	 * 更新日志线程
	 * 
	 * @author lin.r.x
	 *
	 */
	private static class WorkLogUpdateThread implements Runnable {
		private WorkLog workLog;
		private WorkLogService workLogService;

		public WorkLogUpdateThread(WorkLog workLog, WorkLogService workLogService) {
			this.workLog = workLog;
			this.workLogService = workLogService;
		}

		@Override
		public void run() {
			workLogService.update(workLog);		
		}
	}
	
}
